package com.xyxy.platform.openapi.common.security;

import com.alibaba.fastjson.JSON;
import com.xyxy.platform.modules.core.Constants;
import com.xyxy.platform.modules.core.cache.memcached.SpyMemcachedClient;
import com.xyxy.platform.modules.core.utils.ResponseUtils;
import com.xyxy.platform.modules.core.web.MediaTypes;
import com.xyxy.platform.modules.service.member.MemberService;
import com.xyxy.platform.openapi.AppConstants;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 简介: 权限拦截,切点类
 *
 * @Author Caizhenegda
 * @Date 2015-12-32 00:29
 * @Version 1.0
 */
@Aspect
@Component
public class PermissionAspect {

    private static final Logger logger = LoggerFactory.getLogger(PermissionAspect.class);

    @Autowired
    private MemberService memberService;

    /**
     * 类上注解情形
     */
    //@Pointcut("@within(com.xyxy.platform.openapi.common.security.RequiresPermissions)")
    @Pointcut("execution(* com.xyxy.platform.openapi..*controller..*.*(..)) && @within(com.xyxy.platform.openapi.common.security.RequiresPermissions)")
    public void aspect() {
    }

    /**
     * 方法上注解情形
     */
    @Pointcut("execution(* com.xyxy.platform.openapi..*controller..*.*(..)) && @annotation(com.xyxy.platform.openapi.common.security.RequiresPermissions)")
    public void aspect2() {
    }

    /**
     * aop 实际拦截两种情形
     */
    @Around("aspect() || aspect2()")
    public Object doBefore(ProceedingJoinPoint point) throws Throwable, Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.setCharacterEncoding(Constants.ENCODING);
        response.setContentType(MediaTypes.JSON_UTF_8);
        // content type 根据 method 返回值类型进行判断, 待扩展

        HttpSession session = request.getSession();
        Object target = point.getTarget();
        String methodName = point.getSignature().getName();
        Class<?> classz = target.getClass();
        Method method = ((MethodSignature) point.getSignature()).getMethod();
            if (classz != null && method != null) {
                //需要进行拦截的权限
                Map<Integer, Permissions> permissionMap = new LinkedHashMap<>();

                //类名上是否标注 权限拦截注解
                boolean classExist = classz.isAnnotationPresent(RequiresPermissions.class);
                //方法名上是否标注 权限拦截注解
                boolean methodExist = method.isAnnotationPresent(RequiresPermissions.class);

                //如果方法和类声明中同时存在这个注解，那么中和两者注解中需要进行拦截的权限注解
                if (classExist) {
                    RequiresPermissions requiresPermissions = classz.getAnnotation(RequiresPermissions.class);
                    for (Permissions permission : requiresPermissions.permissions()) {
                        permissionMap.put(permission.ordinal(), permission);
                    }
                }
                if (methodExist) {
                    RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
                    for (Permissions permission : requiresPermissions.permissions()) {
                        permissionMap.put(permission.ordinal(), permission);
                    }
                }
                List<Permissions> permissionsList = new ArrayList<>(permissionMap.values());
                //进行权限判断
                boolean success = verifyPermissions(permissionsList, request, response);
                if (success) {
                        //放行
                        return point.proceed();

                }

            }

        //中断
        return null;
    }

    /**
     * 权限判断入口
     *
     * @param permissionsList
     * @param request
     * @param response
     * @return
     */
    private boolean verifyPermissions(List<Permissions> permissionsList, HttpServletRequest request, HttpServletResponse response) {
        boolean result = true;
        for (Permissions p : permissionsList) {
            switch (p) {
                case LOGIN:
                    result = verifyLoginPermission(request, response);
                    break;
                case BANK_CARD:
                    result = verifyBankCardBind(request, response);
                    break;
            }
            if (!result) break;
        }
        return result;
    }

    /**
     * 银行卡绑定验证
     *
     * @param request
     * @param response
     * @return
     */
    private boolean verifyBankCardBind(HttpServletRequest request, HttpServletResponse response) {
        ServletOutputStream outputStream = null;
        Long userId = 1l;// 获得用户ID, 以及银行卡绑定信息
        try {
            outputStream = response.getOutputStream();
            outputStream.write(JSON.toJSONString(ResponseUtils.jsonFail("result test", "银行卡未绑定!")).getBytes());
        } catch (IOException e) {
            logger.error("银行卡绑定验证失败: {}", e.getMessage());
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                logger.error("关闭响应流失败, {}", e.getMessage());
            }
        }
        return false;
    }

    /**
     * 登录权限判断
     *
     * @param request
     * @param response
     * @return
     */
    private boolean verifyLoginPermission(HttpServletRequest request, HttpServletResponse response) {
        ServletOutputStream outputStream = null;
        String token = request.getHeader(AppConstants.REQUEST_TOKEN_KEY);
        if (StringUtils.isNotEmpty(token) && null != memberService.getMemberByToken(token)) {
            return true;
        } else {
            try {
                outputStream = response.getOutputStream();
                outputStream.write(JSON.toJSONString(ResponseUtils.jsonFail(null, "token失效或不存在, 请重新获取!")).getBytes());
            } catch (IOException e) {
                logger.error("登录(token)权限验证失败: {}", e.getMessage());
            } finally {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    logger.error("关闭响应流失败, {}", e.getMessage());
                }
            }
            return false;
        }
    }


}
